package com.junbao.message.infrastructure.util;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class JdbcUtils {

	private static final Logger LOGGER = LoggerFactory.getLogger(JdbcUtils.class);

	private static Map<String, DataSource> dbDataSource = new ConcurrentHashMap<String, DataSource>();
	// 它是事务专用连接！
	private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();

	/**
	 * 从连接池获取数据源
	 * 
	 * @param sourceName 数据源的名称
	 * @return
	 * @throws Exception
	 */
	public static DataSource getDataSource(String sourceName) throws Exception {
		try {
			if (dbDataSource.get(sourceName) != null) {
				return dbDataSource.get(sourceName);
			}
			synchronized (JdbcUtils.class) {
				if (dbDataSource.get(sourceName) == null) {
					dbDataSource.put(sourceName, new ComboPooledDataSource(sourceName));
				}
			}
			return dbDataSource.get(sourceName);
		} catch (Exception e) {
			LOGGER.error("根据数据库名称获取数据库资源失败，数据库名称 ：" + sourceName, e);
			throw new Exception("根据数据库名称获取数据库资源失败，数据库名称 ：" + sourceName);
		}
	}

	/**
	 * 使用连接池返回一个连接对象
	 * 
	 * @return
	 * @throws SQLException
	 */
	public static Connection getConnection(String dataSourceName) throws Exception {
		try {
			Connection con = tl.get();
			// 当con不等于null，说明已经调用过beginTransaction()，表示开启了事务！
			if (con != null)
				return con;
			return getDataSource(dataSourceName).getConnection();
		} catch (Exception e) {
			LOGGER.error("获取数据库连接失败！", e);
			throw new SQLException("获取数据库连接失败！");
		}
	}

	/**
	 * 开启事务 1. 获取一个Connection，设置它的setAutoComnmit(false) 2. 还要保证dao中使用的连接是我们刚刚创建的！ -------------- 1. 创建一个Connection，设置为手动提交 2.
	 * 把这个Connection给dao用！ 3. 还要让commitTransaction或rollbackTransaction可以获取到！
	 * 
	 * @throws SQLException
	 */
	public static void beginTransaction(String dataSourceName) throws Exception {
		try {
			Connection con = tl.get();
			if (con != null) {
				con.close();
				tl.remove();
				//throw new SQLException("已经开启了事务，就不要重复开启了！");
			}
			con = getConnection(dataSourceName);
			con.setAutoCommit(false);
			tl.set(con);
		} catch (Exception e) {
			LOGGER.error("数据库事物开启失败！", e);
			throw new SQLException("数据库事物开启失败！");
		}
	}

	/**
	 * 提交事务 1. 获取beginTransaction提供的Connection，然后调用commit方法
	 * 
	 * @throws SQLException
	 */
	public static void commitTransaction() throws SQLException {
		Connection con = tl.get();
		try {
			if (con == null){
				//throw new SQLException("还没有开启事务，不能提交！");
				LOGGER.info("还没有开启事务，不能提交！");
				return;
			}
			con.commit();
		} catch (Exception e) {
			LOGGER.error("数据库事物提交失败！", e);
			throw new SQLException("数据库事物提交失败！");
		} finally {
			if (con != null) {
				con.close();
			}
			tl.remove();
		}
	}

	/**
	 * 提交事务 1. 获取beginTransaction提供的Connection，然后调用rollback方法
	 * 
	 * @throws SQLException
	 */
	public static void rollbackTransaction() throws SQLException {
		Connection con = tl.get();
		try {
			if (con == null){
				//throw new SQLException("还没有开启事务，不能回滚！");
				LOGGER.info("还没有开启事务，不能回滚！");
				return;
			}
			con.rollback();
		} catch (Exception e) {
			LOGGER.error("数据库事物回滚失败！", e);
			throw new SQLException("数据库事物回滚失败！");
		} finally {
			if (con != null) {
				con.close();
			}
			tl.remove();
		}
	}

	/**
	 * 释放连接　
	 * 
	 * @param connection
	 * @throws SQLException
	 */
	public static void releaseConnection(Connection connection) throws SQLException {
		try {
			Connection con = tl.get();
			// 判断它是不是事务专用，如果是，就不关闭！ 如果不是事务专用，那么就要关闭！
			// 如果con == null，说明现在没有事务，那么connection一定不是事务专用的！
			if (con == null)
				connection.close();
			// 如果con != null，说明有事务，那么需要判断参数连接是否与con相等，若不等，说明参数连接不是事务专用连接
			if (con != connection)
				connection.close();
		} catch (Exception e) {
			LOGGER.error("数据库连接释放失败！", e);
			throw new SQLException("数据库连接释放失败！");
		}
	}

}
